package com.jk.common.aspect;

import com.jk.common.datasource.DynamicDataSourceContextHolder;
import com.jk.common.datasource.RoutingStrategy;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

/**
 * 动态数据源切面。控制使用Master还是Slave
 *
 * 切换规则如下：
 * 1. 如果事务管理器中指定了事务策略，则采用事务策略标记为ReadOnly=true的方法用Slave，其他的使用Master
 * 2. 如果事务管理器中未指定事务策略，则全部使用Master
 * @author cuiP
 * Created by JK on 2017/6/21.
 */
@Slf4j
public class DynamicDataSourceAspect {

    /**
     * 环绕通知实现
     * @param pjp
     * @return
     * @throws Throwable
     */
    public Object aroundRoutingDataSource(ProceedingJoinPoint pjp) throws Throwable {

        // 获取切入的 Method
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        Transactional annotation = method.getAnnotation(Transactional.class);

        //请求的方法名全路径
        String className = pjp.getTarget().getClass().getName();
        String methodName = signature.getName();

        //当前切换到的数据源
        String dataSource = "";
        //判断当前事务策略是否为readOnly，若是则走从库，否则走主库
        if (annotation != null && annotation.readOnly()) {
            //标记为从库
            DynamicDataSourceContextHolder.setDataSource(RoutingStrategy.SLAVE);
            dataSource = "slaveDataSource";
        } else {
            //标记为主库
            DynamicDataSourceContextHolder.setDataSource(RoutingStrategy.MASTER);
            dataSource = "masterDataSource";
        }

        log.info("class:{} method:{} 切换数据源 >> {} 成功!", className, methodName, dataSource);

        //执行实际方法
        Object resBody =  pjp.proceed();

        //重置数据源
        log.info("Revert DataSource...");
        DynamicDataSourceContextHolder.clearDataSource();
        return resBody;
    }
}
